#include "SayBehaviour.h"

#include <string.h>

// Posiela zvukovu informaciu
// POZN.: Neoptimalne vyuzita dlzka spravy. Okrem toho najdolezitejsia je pozicia hraca, ostatne parametre hraca
// nie je podla mna potrebne prenasat.
/*
 *	vytvori a posle spravu ak chce nieco poslat
 *
 */
void SayBehaviour::Behave()
{
// Mal by som nieco povedat?
	if(!ShouldSendInfo())
		return;
	
	// Vytvori spravu. Uklada udaje do 3-stavovych a 2-stavovych premennych. Kombinuje premenne (2x 3-stavovu a
	// 3x dvojstavovu) do cisla z intervalu <0, 71>. Prekonvertuje cisla do validnych znakov (okrem '_' a ' ')
	// Pozri aj PlayerSkills::OnHear()

	unsigned char parts[10][6];
	int i;
	for(i = 0; i < 10; i++)
	{
		parts[i][0] = 0xff;
		parts[i][1] = parts[i][2] = parts[i][3] = parts[i][4] = parts[i][5] = 0;
	}

	// Alokacia casti:
	// - = volne, X = hracova x-ova suradnica, Y = hracova y-ova suradnica
	// D = hracova smer, S = hracova rychlost
	// 1(3) XYDS----YY
	// 2(3) XYDS----DX
	// 3(2) XYDS----DX
	// 4(2) XYDS----SX
	// 5(2) XYDS----YX
	// Toto musi byt to iste v OnHear().

//	DBGN("---");
//	DBGN("SEND INFO: %0.3f, %0.3f, %0.3f, %0.3f", world->me->pos.GetX(), world->me->pos.GetY(), world->me->vel.GetX(), world->me->vel.GetY());

	// X suradnica hraca (vyuziva 72,3,2,2,2 pozri hore)
	int tmp = int((world->me->pos.GetX() - world->params->flags[L0].GetX()) * float(72 * 3 * 2 * 2 * 2) / 
		(world->params->flags[R0].GetX() - world->params->flags[L0].GetX()) + 0.5);
//	DBGN("tmp_x %i", tmp);
	parts[9][5] = tmp % 2; tmp /= 2;
	parts[9][4] = tmp % 2; tmp /= 2;
	parts[9][3] = tmp % 2; tmp /= 2;
	parts[9][2] = tmp % 3; tmp /= 3;
	parts[0][0] = tmp % 72; tmp /= 72;

	// Y suradnica hraca (vyuziva 72,3,3,2 pozri hore)
	tmp = int((world->me->pos.GetY() - world->params->flags[T0].GetY()) * float(72 * 3 * 3 * 2) / 
		(world->params->flags[B0].GetY() - world->params->flags[T0].GetY()) + 0.5);
//	DBGN("tmp_y %i", tmp);
	parts[8][5] = tmp % 2; tmp /= 2;
	parts[8][1] = tmp % 3; tmp /= 3;
	parts[9][1] = tmp % 3; tmp /= 3;
	parts[1][0] = tmp % 72; tmp /= 72;

	// Smer hraca (vyuziva 72,3,2 pozri hore)
	float angle = world->me->vel.GetAngle().GetRad();
	while(angle < 0)
		angle += 2.0f * M_PI; 
	while(angle > 2.0f * M_PI)
		angle -= 2.0f * M_PI;
	
	tmp = int(angle * float(72 * 3 * 2) / (2.f * M_PI) + 0.5);
//	DBGN("tmp_dir %i ang %0.3f", tmp, angle);
	parts[8][3] = tmp % 2; tmp /= 2;
	parts[8][2] = tmp % 3; tmp /= 3;
	parts[2][0] = tmp % 72; tmp /= 72;

	// Rychlost hraca (vyuziva 72,2 pozri hore)
	tmp = int(world->me->vel.GetLength() * float(72 * 2) /
		(world->params->server->player_speed_max + world->params->player->player_speed_max_delta_max) + 0.5);
//	DBGN("tmp_spd %i", tmp);
	parts[8][4] = tmp % 2; tmp /= 2;
	parts[3][0] = tmp % 72; tmp /= 72;

	//world->ball->pos.GetX(), world->ball->pos.GetY(), world->ball->vel.GetX(), world->ball->vel.GetY(), ball.age);

	// Prekonvertuje casti do cisiel a zakoduje ich do znakov
	char msg[11];
	memset(msg, 0, 11);
	for(i = 0; i < 10; i++)
	{
		if(parts[i][0] == 0xff)
			parts[i][0] = (((parts[i][5] * 2 + parts[i][4]) * 2 + parts[i][3]) * 3 + parts[i][2]) * 3 + parts[i][1];

		if(parts[i][0] <= 25)
			msg[i] = 'a' + char(parts[i][0]);
		else if((parts[i][0] >= 26) && (parts[i][0] <= 51))
			msg[i] = 'A' + char(parts[i][0] - 26);
		else if((parts[i][0] >= 52) && (parts[i][0] <= 61))
			msg[i] = '0' + char(parts[i][0] - 52);
		else if(parts[i][0] == 62)
			msg[i] = '+'; 
		else if(parts[i][0] == 63) 
			msg[i] = '-';
		else if(parts[i][0] == 64)
			msg[i] = '*'; 
		else if(parts[i][0] == 65)
			msg[i] = '/';
		else if(parts[i][0] == 66)
			msg[i] = '('; 
		else if(parts[i][0] == 67)
			msg[i] = ')';
		else if(parts[i][0] == 68)
			msg[i] = '.'; 
		else if(parts[i][0] == 69)
			msg[i] = '?';
		else if(parts[i][0] == 70)
			msg[i] = '<'; 
		else if(parts[i][0] == 71) 
			msg[i] = '>';
		else
		{ 
			WARNN("failed encoding for say (%i->%i)", i, (int) parts[i][0]);
			return;
		}
	}

/*	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][0]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][1]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][2]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][3]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][4]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][5]); DBGN("");
*/
	msg[10] = '\0';
	commandGenerator->Say(msg);
}


/*
 *	zisti,ci je potrebne poslat spravu
 *
 */
bool SayBehaviour::ShouldSendInfo()
{
	if(world->ball->pos.GetX() < 0.f)
	{
		// Lopta je na nasej polovici. Hraci 2 az 11 by mali posielat zvukove spravy kazdych 20 cyklov.
		int time = world->state->GetSimTime() % 20;
		
		if(time == (world->me->GetUniform() - 2) * 2)
			return true;
		else
			return false;
	}
	else
	{
		// Lopta je na polovici supera. Hraci na ich strane a na opacnej strane od lopty by mali kricat
		// kazde dva cykly.
		if(!world->ball->IsValid())
		{
//			SHOUT_DBGN("SHT %i: invalid ball", world->state->GetSimTime());
			return false;
		}

		if(world->me->pos.GetX() < 0.f)
		{
//			SHOUT_DBGN("SHT %i: in defense", world->state->GetSimTime()); return false;
		}

		if(world->me->pos.GetY() * world->ball->pos.GetY() > 0.f)
		{
//			SHOUT_DBGN("SHT %i: same side", world->state->GetSimTime());
			return false;
		}

		static int lastTime = -1000;
		
		if(world->state->GetSimTime() - lastTime < 2)
		{
//			SHOUT_DBGN("SHT %i: too often", world->state->GetSimTime());
			return false;
		}

//		SHOUT_DBGN("SHT %i: shouting", world->state->GetSimTime());
		return true;
	}
}
